package com.fly.sealedcontainer.handler;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fly.sealedcontainer.entity.ApiResponse;
import com.fly.sealedcontainer.entity.Image;
import com.fly.sealedcontainer.mapper.ImageMapper;
import com.fly.sealedcontainer.util.ApplicationContextUtil;
import com.fly.sealedcontainer.util.MyUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 核心流程控制器
 */
@Slf4j
public class Handler {

    /**
     * 搜索关键词
     */
    private final String word;

    /**
     * 计数器，用于记录成功下载的数量
     */
    private final AtomicInteger count;

    /**
     * 计数器，用于重复图片的数量
     */
    private final AtomicInteger repeatedCount;

    /**
     * md5列表，用于每次对比是否重复
     */
    private static List<String> md5List;

//    static {
//        // 初始化md5对比列表
//        ImageMapper imageMapper = ApplicationContextUtil.getBean(ImageMapper.class);
//        List<Image> imageList = imageMapper.selectList(Wrappers.emptyWrapper());
//        md5List = imageList.stream().map(Image::getMd5).collect(Collectors.toList());
//    }

    public Handler(String word) {
        this.word = word;
        this.count = new AtomicInteger(0);
        this.repeatedCount = new AtomicInteger(0);
    }

    /**
     * 执行流水线方法
     */
    public void execute() {
        log.info("<{}>爬虫开始", word);

        // 调用api搜索图片，解析响应消息
        ApiResponse apiResponse = search();
        if (apiResponse == null) {
            return;
        }
        List<ApiResponse.BaiduImage> imageList = apiResponse.getImageList();
        for (ApiResponse.BaiduImage baiduImage : imageList) {
            String imageUrl = baiduImage.getUrl();
            if (!StringUtils.hasText(imageUrl)) {
                continue;
            }
//            // 计算md5
//            String md5 = calculateMd5(imageUrl);
//            synchronized (Handler.class) {
//                // 检查图片是否重复 todo 这样能否解决多线程下的不安全？
//                boolean isRepeated = isMd5Repeated(md5);
//                if (isRepeated) {
//                    repeatedCount.incrementAndGet();
//                    continue;
//                }
//                // 保存数据库
//                saveMd5(baiduImage, word, md5);
//                md5List.add(md5);
//            }
            // 下载图片
            download(baiduImage, word);
        }

//        log.info("<{}>爬虫结束,有{}张图片重复,成功下载{}张图片", word, repeatedCount.get(), count.get());
        log.info("<{}>爬虫结束,成功下载{}张图片", word, count.get());
    }

    /**
     * 根据关键词搜索图片
     */
    private ApiResponse search() {
        // 拼接搜索url
        String url = "https://image.baidu.com/search/acjson?tn=resultjson_com&logid=8987383620925960897&ipn=rj&ct=201326592&is=&fp=result&fr=" +
                "&word=" + word +
                "&queryWord=" + word +
                "&cl=2&lm=&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=&hd=&latest=&copyright=&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&expermode=&nojc=&isAsync=" +
                "&pn=0" + // 开始条数
                "&rn=60" + // 显示数量（最大60）
                "&gsm=3c&1640314046637=";
        try {
            Document document = Jsoup.connect(url).get();
            Element body = document.body();
            log.debug("<{}>接口响应数据:\n{}", word, body);
            ObjectMapper objectMapper = MyUtil.objectMapper();
            ApiResponse apiResponse = objectMapper.readValue(body.text(), ApiResponse.class);
            return apiResponse;
        } catch (IOException e) {
            log.error("<{}>搜索图片失败", word);
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 计算图片的md5
     */
    private String calculateMd5(String imageUrl) {
        String md5 = null;
        InputStream inputStream = null;
        try {
            URL url = new URL(imageUrl);
            URLConnection connection = url.openConnection();
            // 获取输入流
            inputStream = connection.getInputStream();
            // 计算md5
            md5 = DigestUtils.md5DigestAsHex(inputStream);
        } catch (MalformedURLException e) {
            log.error("图片url错误:{}", imageUrl);
            e.printStackTrace();
        } catch (IOException e) {
            log.error("图片connection打开失败:{}", imageUrl);
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return md5;
    }

    /**
     * 检查md5是否重复
     *
     * @param md5 图片md5
     * @return true重复，false不重复
     */
    private boolean isMd5Repeated(String md5) {
        return md5List.contains(md5);
    }

    /**
     * 保存图片md5信息到数据库
     *
     * @param baiduImage 图片对象
     * @param word       搜索关键词
     * @param md5        md5
     */
    private void saveMd5(ApiResponse.BaiduImage baiduImage, String word, String md5) {
        ImageMapper imageMapper = ApplicationContextUtil.getBean(ImageMapper.class);
        Image image = new Image();
        image.setUrl(baiduImage.getUrl());
        image.setWord(word);
        image.setTitle(baiduImage.getTitle());
        image.setMd5(md5);
        imageMapper.insert(image);
    }

    /**
     * 下载图片
     *
     * @param baiduImage 图片对象
     * @param word       搜索关键词
     */
    private void download(ApiResponse.BaiduImage baiduImage, String word) {
        // 图片下载到本地的路径
        String imagePath = MyUtil.newImagePath(word, baiduImage.getPictureType());
        try {
            String imageUrl = baiduImage.getUrl();
            log.debug("<{}>图片url:{}", word, imageUrl);
            if (!StringUtils.hasText(imageUrl)) {
                return;
            }
            URL urlObject = new URL(imageUrl);
            File imageFile = new File(imagePath);
            log.debug("<{}>图片本地路径:{}", word, imagePath);
            // 通过图片链接下载到本地
            FileUtils.copyURLToFile(urlObject, imageFile);
            count.incrementAndGet();
        } catch (IOException e) {
            log.error("图片下载失败");
            e.printStackTrace();
        }
    }
}
